home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-05 / drivers1.zip / 3C503.ASM < prev    next >
Assembly Source File  |  1992-01-10  |  17KB  |  536 lines

  1. ;History:512,1
  2. version    equ    4
  3.  
  4.     include    defs.asm
  5.  
  6. ;/* PC/FTP Packet Driver source, conforming to version 1.05 of the spec,
  7. ;*  for the 3-Com 3C503 interface card.
  8. ;*  Robert C Clements, K1BC, 14 February, 1989
  9. ;*  Portions (C) Copyright 1988, 1989 Robert C Clements
  10. ;*
  11. ;  Copyright, 1988-1992, Russell Nelson, Crynwr Software
  12.  
  13. ;   This program is free software; you can redistribute it and/or modify
  14. ;   it under the terms of the GNU General Public License as published by
  15. ;   the Free Software Foundation, version 1.
  16. ;
  17. ;   This program is distributed in the hope that it will be useful,
  18. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20. ;   GNU General Public License for more details.
  21. ;
  22. ;   You should have received a copy of the GNU General Public License
  23. ;   along with this program; if not, write to the Free Software
  24. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25.  
  26. ;* Change history:
  27. ;*  Updated to driver spec version 1.08 Feb. 17, 1989 by Russell Nelson.
  28. ;*  Changes 27 Jul 89 by Bob Clements (/Rcc)
  29. ;*    Added Thick versus Thin Ethernet switch  27 Jul 89 by Bob Clements (/Rcc)
  30. ;*    Added call to memory_test.
  31. ;*    Added rcv_mode logic.  Started, but didn't finish, multicast logic. 
  32. ;*      Fixed get_address to return current, not PROM, address.
  33. ;*      Minor races fixed.
  34.  
  35. comment /
  36. From: "James A. Harvey" <IJAH400@indyvax.iupui.edu>
  37. Subject: Patches for 6.x packet drivers; lockup problem fixed!
  38.  
  39. Now for the best part, the lockup problem fix.  I think this may be one that
  40. I keep hearing about that for most people the machine locks up for a minute
  41. on startup, but then continues.  For me it was worse because it appears that
  42. the "recovery" time is only short on heavily loaded networks.  The lockup is
  43. caused by the "first page for RX" being set improperly in etopen; I finally
  44. figured it out by looking at code from other drivers that used the DS8390
  45. chip.  One must switch to the page 1 command registers first.
  46. /
  47.  
  48.  
  49. code    segment    word public
  50.     assume    cs:code, ds:code
  51.  
  52. ; Stuff specific to the 3-Com 3C503 Ethernet controller board
  53. ; WD version in C by Bob Clements, K1BC, May 1988 for the KA9Q TCP/IP package
  54. ; 3Com version based on WD8003E version in .ASM, also by Bob Clements, dated
  55. ;  19 August 1988.  The WD and 3Com cards both use the National DS8390.
  56.  
  57. ; Symbol prefix "EN" is for Ethernet, National chip
  58. ; Symbol prefix "E33" is for _E_thernet, _3_Com 50_3_
  59. ; Symbol prefix "E33G" is for registers in the Gate array ASIC.
  60.  
  61. ; The E33 registers - For the ASIC on the 3C503 card:
  62. ; Offsets from the board's base address, which can be set by
  63. ; jumpers to be one of the following 8 values (hex):
  64. ;  350, 330, 310, 300, 2E0, 2A0, 280, 250
  65. ; Factory default address is 300H.
  66. ; The card occupies a block of 16 I/O addresses.
  67. ; It also occupies 16 addresses at base+400 through base+40F.
  68. ; These high-addressed registers are in the ASIC.
  69. ; Recall that the normal PC I/O decoding is only 10 bits. The 11'th
  70. ; bit (400H) can be used on the same card for additional registers.
  71. ; This offset requires word, not byte, arithmetic
  72. ; on the DX register for the setport macro. Current SETPORT is OK.
  73.  
  74. ; The card can also be jumpered to have the shared memory disabled
  75. ; or enabled at one of four addresses: C8000, CC000, D8000 or DC000.
  76. ; This version of the driver REQUIRES the shared memory to be 
  77. ; enabled somewhere.
  78. ; The card can be operated using direct I/O instructions or by
  79. ; using the PC's DMA channels instead of the shared memory, but
  80. ; I haven't included the code for those other two methods. 
  81. ; They would be needed in a system where all four possible addresses
  82. ; for the shared memory are in use by other devices.  /Rcc
  83.  
  84. ; Blocks of I/O addresses:
  85.  
  86. E33GA        equ    400h    ; Registers in the gate array.
  87. E33_SAPROM    equ    000h    ; Window on station addr prom (if
  88.                 ; E33G_CNTRL bits 3,2 = 0,1
  89.  
  90. ; These appear at Base+0 through Base+0F when bits 3,2 of
  91. ; E33G_CNTRL are 0,0.
  92.  
  93. EN_OFF        equ    0h
  94.  
  95. ENDCFG_BM8    equ    48h
  96.  
  97.     include    8390.inc
  98.  
  99. ; Registers in the 3-Com custom Gate Array
  100.  
  101. E33G_STARTPG    equ E33GA+00h    ; Start page, must match EN0_STARTPG
  102. E33G_STOPPG    equ E33GA+01h    ; Stop  page, must match EN0_STOPPG
  103. E33G_NBURST    equ E33GA+02h    ; Size of DMA burst before relinquishing bus
  104. E33G_IOBASE    equ E33GA+03h    ; Bit coded: where I/O regs are jumpered.
  105.                 ; (Which you have to know already to read it)
  106. E33G_ROMBASE    equ E33GA+04h    ; Bit coded: Where/whether EEPROM&DPRAM exist
  107. E33G_GACFR    equ E33GA+05h    ; Config/setup bits for the ASIC GA
  108. E33G_CNTRL    equ E33GA+06h    ; Board's main control register
  109. E33G_STATUS    equ E33GA+07h    ; Status on completions.
  110. E33G_IDCFR    equ E33GA+08h    ; Interrupt/DMA config register
  111.                 ; (Which IRQ to assert, DMA chan to use)
  112. E33G_DMAAH    equ E33GA+09h    ; High byte of DMA address reg
  113. E33G_DMAAL    equ E33GA+0ah    ; Low byte of DMA address reg
  114. E33G_VP2    equ E33GA+0bh    ; Vector pointer - for clearing RAM select
  115. E33G_VP1    equ E33GA+0ch    ;  on a system reset, to re-enable EPROM.
  116. E33G_VP0    equ E33GA+0dh    ;  3Com says set this to Ctrl-Alt-Del handler
  117. E33G_FIFOH    equ E33GA+0eh    ; FIFO for programmed I/O data moves ...
  118. E33G_FIFOL    equ E33GA+0fh    ; .. low byte of above.
  119.  
  120. ; Bits in E33G_CNTRL register:
  121.  
  122. ECNTRL_RESET    equ    001h    ; Software reset of the ASIC and 8390
  123. ECNTRL_THIN    equ    002h    ; Onboard thin-net xcvr enable
  124. ECNTRL_SAPROM    equ    004h    ; Map the station address prom
  125. ECNTRL_DBLBFR    equ    020h    ; FIFO configuration bit
  126. ECNTRL_OUTPUT    equ    040h    ; PC-to-3C503 direction if 1
  127. ECNTRL_START    equ    080h    ; Start the DMA logic
  128.  
  129. ; Bits in E33G_STATUS register:
  130.  
  131. ESTAT_DPRDY    equ    080h    ; Data port (of FIFO) ready
  132. ESTAT_UFLW    equ    040h    ; Tried to read FIFO when it was empty
  133. ESTAT_OFLW    equ    020h    ; Tried to write FIFO when it was full
  134. ESTAT_DTC    equ    010h    ; Terminal Count from PC bus DMA logic
  135. ESTAT_DIP    equ    008h    ; DMA In Progress
  136.  
  137. ; Bits in E33G_GACFR register:
  138.  
  139. EGACFR_NORM    equ    049h    ; Enable 8K shared mem, no DMA TC int
  140. EGACFR_IRQOFF    equ    0c9h    ; Above, and disable 8390 IRQ line
  141.  
  142. ; Shared memory management parameters
  143.  
  144. SM_TSTART_PG    equ    020h    ; First page of TX buffer
  145. SM_RSTART_PG    equ    026h    ; Starting page of RX ring
  146. SM_RSTOP_PG    equ    040h    ; Last page +1 of RX ring
  147.  
  148. ; End of 3C503 parameter definitions
  149.  
  150. pause_    macro
  151.     jmp    $+2
  152. endm
  153.  
  154. longpause macro
  155.     push    cx
  156.     mov    cx,0
  157.     loop    $
  158.     pop    cx
  159. endm
  160.  
  161. ram_enable    macro
  162.     setport    E33G_GACFR    ; Make sure gate array is set up and
  163.     mov al,    EGACFR_NORM    ;  the RAM is enabled (not EPROM)
  164.     out dx,    al        ; ..
  165.     endm
  166.  
  167.  
  168. reset_8390    macro
  169.     loadport        ; First, pulse the board reset
  170.     setport    E33G_CNTRL
  171.     mov    al,thin_bit        ; Thick or thin cable bit
  172.     or    al,ECNTRL_RESET
  173.     out    dx,al            ; Turn on board reset bit
  174.     mov    al,thin_bit        ; Thick or thin cable bit
  175.     out    dx,al            ; Turn off board reset bit
  176.     call    do_reset
  177.     loadport
  178.     endm
  179.  
  180. terminate_board    macro
  181.     endm
  182.  
  183. ; The following three values may be overridden from the command line.
  184. ; If they are omitted from the command line, these defaults are used.
  185. ; The shared memory base is set by a jumper.  We read it from the
  186. ; card and set up accordingly.
  187.  
  188.     public    int_no, io_addr, thin_not_thick
  189. int_no        db    2,0,0,0        ; Interrupt level
  190. io_addr        dw    0300h,0        ; I/O address for card (jumpers)
  191. thin_not_thick    dw    1,0        ; Non-zero means thin net
  192.     public    mem_base
  193. mem_base    dw    00000h,0    ; Shared memory addr (jumpers)
  194. ; (Not changeable by software in 3C503)    ; (0 if disabled by jumpers)
  195. thin_bit    db    ECNTRL_THIN    ; Default to thin cable
  196.  
  197.     public    driver_class, driver_type, driver_name, driver_function, parameter_list
  198. driver_class    db    BLUEBOOK, IEEE8023, 0        ;from the packet spec
  199. driver_type    db    12        ;from the packet spec
  200. driver_name    db    '3C503',0    ;name of the driver.
  201. driver_function    db    2
  202. parameter_list    label    byte
  203.     db    1    ;major rev of packet driver
  204.     db    9    ;minor rev of packet driver
  205.     db    14    ;length of parameter list
  206.     db    EADDR_LEN    ;length of MAC-layer address
  207.     dw    GIANT    ;MTU, including MAC headers
  208.     dw    MAX_MULTICAST * EADDR_LEN    ;buffer size of multicast addrs
  209.     dw    0    ;(# of back-to-back MTU rcvs) - 1
  210.     dw    0    ;(# of successive xmits) - 1
  211. int_num    dw    0    ;Interrupt # to hook for post-EOI
  212.             ;processing, 0 == none,
  213.  
  214. is_186        db    0
  215.  
  216.     include    movemem.asm
  217.  
  218. block_output:
  219. ;enter with cx = byte count, ds:si = buffer location, ax = buffer address
  220.     assume    ds:nothing
  221.     cmp    mem_base,0        ;memory or I/O?
  222.     je    block_o            ;I/O.
  223.     mov    es,mem_base        ; Set up ES:DI at the shared RAM
  224.     mov    di,ax            ; ..
  225.     loadport            ; Set up for address of TX buffer.
  226.     ram_enable            ; Make sure the RAM is actually there.
  227.     call    movemem
  228.     clc
  229.     ret
  230.  
  231. block_o:
  232.     setport    E33G_CNTRL
  233.     mov    al,thin_bit
  234.     or    al,0c0h            ;start dma, write to board.
  235.     out    dx,al
  236.  
  237. ;;; we should really have another copy of this loop for 186 I/O instructions.
  238.  
  239.     setport    E33G_STATUS
  240. block_o_0:
  241.     jcxz    block_o_2        ;if there is none, exit.
  242.     in    al,dx            ;wait for the FIFO to be ready.
  243.     test    al,ESTAT_DPRDY
  244.     je    block_o_0
  245.     setport    E33G_FIFOH        ;now get ready to read data.
  246.     cmp    cx,8            ;do we have eight more to do?
  247.     jb    block_o_1        ;no, do them one by one.
  248.     lodsw                ;yes, output eight all at once.
  249.     out    dx,ax
  250.     lodsw
  251.     out    dx,ax
  252.     lodsw
  253.     out    dx,ax
  254.     lodsw
  255.     out    dx,ax
  256.     sub    cx,8            ;reduce the count by what we write.
  257.     setport    E33G_STATUS        ;go back to the status bit.
  258.     jmp    block_o_0
  259. block_o_1:
  260.     lodsb
  261.     out    dx,ax
  262.     loop    block_o_1
  263. block_o_2:
  264.     loadport
  265.     setport    E33G_CNTRL
  266.     mov    al,thin_bit        ;stop dma.
  267.     out    dx,al
  268.     ret
  269.  
  270.  
  271. block_input:
  272. ;enter with cx = byte count, es:di = buffer location, ax = board address.
  273.     cmp    mem_base,0        ; memory or I/O
  274.     je    block_i            ; I/O
  275.     push    ds
  276.     assume    ds:nothing
  277.     mov    ds,mem_base        ; ds:si points at first byte to move
  278.     mov    si,ax
  279.  
  280.     add    ax,cx            ; Find the end of this frame.
  281.     cmp    ah,byte ptr cs:sm_rstop_ptr ; Over the top of the ring?
  282.     jb    rcopy_one_piece        ; Go move it
  283.  
  284. rcopy_wrap:
  285. ; Copy in two pieces due to buffer wraparound.
  286.     mov    ah,byte ptr cs:sm_rstop_ptr ; Compute length of first part
  287.     xor    al,al
  288.     sub    ax,si            ;  as all of the pages up to wrap point
  289.     sub    cx,ax            ; Move the rest in second part
  290.     push    cx            ; Save count of second part
  291.     mov    cx,ax            ; Count for first move
  292.     call    rcopy_subr
  293.     mov    si,SM_RSTART_PG*256    ; Offset to start of first receive page
  294.     pop    cx            ; Bytes left to move
  295. rcopy_one_piece:
  296.     call    rcopy_subr
  297.     pop    ds
  298.     ret
  299.  
  300.  
  301. rcopy_subr:
  302.     shr    cx,1            ; convert byte count to word count
  303.     rep    movsw
  304.     jnc    rcv_wrap_even        ; odd byte left over?
  305.     lodsw                ;   yes, word fetch
  306.     stosb                ;   and byte store
  307. rcv_wrap_even:
  308.     ret
  309.  
  310. block_i:
  311.     ret
  312.  
  313.  
  314.     include    8390.asm
  315.  
  316.     public    usage_msg
  317. usage_msg    db    "usage: 3C503 [-n] [-d] [-w] <packet_int_no> <int_level(2-5)> <io_addr> <thin_net_flag>",CR,LF,'$'
  318.  
  319.     public    copyright_msg
  320. copyright_msg    db    "Packet driver for 3-Com 3C503, version "
  321.         db    '0'+majver,".",'0'+version,".",'0'+dp8390_version,CR,LF
  322.         db    "Portions Copyright 1989, Robert C. Clements, K1BC",CR,LF,'$'
  323.  
  324. cfg_err_msg    db    "3C503 Configuration failed. Check parameters.",CR,LF,'$'
  325. mem_busted_msg    db    "Shared RAM on 3C503 card is defective or there is an address conflict.",CR,LF,'$'
  326.  
  327. int_no_name    db    "Interrupt number ",'$'
  328. io_addr_name    db    "I/O port ",'$'
  329. mem_base_name    db    "Memory address ",'$'
  330.  
  331. thin_msg    db    "Using the built-in transceiver (thinwire)",CR,LF,'$'
  332. thick_msg    db    "Using the external transceiver (thickwire)",CR,LF,'$'
  333.  
  334.  
  335.     extrn    set_recv_isr: near
  336.  
  337. ;enter with si -> argument string, di -> word to store.
  338. ;if there is no number, don't change the number.
  339.     extrn    get_number: near
  340.  
  341. ;enter with dx -> name of word, di -> dword to print.
  342.     extrn    print_number: near
  343.  
  344.     public    parse_args
  345. parse_args:
  346. ;exit with nc if all went well, cy otherwise.
  347.     mov    di,offset int_no    ; May override interrupt channel
  348.     call    get_number
  349.     mov    di,offset io_addr    ; May override I/O address
  350.     call    get_number
  351.     mov    di,offset thin_not_thick    ; May override thick/thin cable flag
  352.     call    get_number
  353.     mov    ax,thin_not_thick    ; Now make the right bit
  354.     cmp    ax,0
  355.     je    parse_thin1        ; If zero, leave bit off
  356.     mov    al,ECNTRL_THIN        ; Else the bit for the card
  357. parse_thin1:
  358.     mov    thin_bit,al        ; Save for setting up the card
  359.  
  360.     clc
  361.     ret
  362.  
  363. do_reset:
  364.     assume    ds:code
  365.     loadport
  366.     cli                ; Protect the E33G_CNTRL contents
  367.     setport E33G_CNTRL        ; Switch control bits to enable SA PROM
  368.     mov al,    thin_bit
  369.     or al,    ECNTRL_SAPROM
  370.     out dx,    al            ; ..
  371.     setport    E33_SAPROM        ; Where the address prom is
  372.  
  373.     cld                ; Make sure string mode is right
  374.     push    cs            ; Point es:di at local copy space
  375.     pop    es
  376.     mov di,    offset curr_hw_addr
  377.     mov cx,    EADDR_LEN        ; Set count for loop
  378. do_reset_1:
  379.     in al,    dx            ; Get a byte of address
  380.     stosb                ; Feed it to caller
  381.     inc    dx            ; Next byte at next I/O port
  382.     loop    do_reset_1        ; Loop over six bytes
  383.  
  384.     loadport            ; Re-establish I/O base after dx mods
  385.     setport E33G_CNTRL        ; Switch control bits to turn off SA PROM
  386.     mov al,    thin_bit
  387.     out dx,    al            ; Turn off SA PROM windowing
  388.     sti                ; Ok for E33G_CNTRL to change now
  389.  
  390.     call    set_8390_eaddr
  391.  
  392.     ret
  393.  
  394. init_card:
  395. ; Now get the board's physical address from on-board PROM into card_hw_addr
  396.     assume    ds:code
  397.     loadport
  398.     cli                ; Protect the E33G_CNTRL contents
  399.     setport E33G_CNTRL        ; Switch control bits to enable SA PROM
  400.     mov al,    thin_bit
  401.     or al,    ECNTRL_SAPROM
  402.     out dx,    al            ; ..
  403.     setport    E33_SAPROM        ; Where the address prom is
  404.  
  405.     cld                ; Make sure string mode is right
  406.     push    cs            ; Point es:di at local copy space
  407.     pop    es
  408.     mov di,    offset curr_hw_addr
  409.     mov cx,    EADDR_LEN        ; Set count for loop
  410. ini_addr_loop:
  411.     in al,    dx            ; Get a byte of address
  412.     stosb                ; Feed it to caller
  413.     inc    dx            ; Next byte at next I/O port
  414.     loop    ini_addr_loop        ; Loop over six bytes
  415.  
  416.     loadport            ; Re-establish I/O base after dx mods
  417.     setport E33G_CNTRL        ; Switch control bits to turn off SA PROM
  418.     mov al,    thin_bit
  419.     out dx,    al            ; Turn off SA PROM windowing
  420.     sti                ; Ok for E33G_CNTRL to change now
  421. ; Point the "Vector Pointer" registers off into the boonies so we
  422. ; don't get the shared RAM disabled on us while we're using it.
  423. ; Ideally a warm boot should reset this too, to get to ROM on this card,
  424. ; but I don't know a guaranteed way to determine that value.
  425.     setport    E33G_VP2
  426.     mov al,    0ffh            ; Point this at the ROM restart location
  427.     out dx,    al            ;  of ffff0h.
  428.     setport E33G_VP1
  429.     out dx,    al
  430.     xor al,    al
  431.     setport E33G_VP0
  432.     out dx,    al
  433. ;Make sure shared memory is jumpered on. Find its address.
  434.     setport E33G_ROMBASE        ; Point at rom/ram cfg reg
  435.     xor    bx,bx
  436.     in al,    dx            ; Read it
  437.     test al,0f0h            ; Any bits on?
  438.     je    memcfg_3        ; no - using I/O.
  439. memcfg_1:
  440.     mov bx,    0c600h            ; Build mem segment here
  441.     test al,0c0h            ; DC00 or D800?
  442.     je    memcfg_2        ; No
  443.     add bx,    01000h            ; Yes, make Dx00
  444. memcfg_2:
  445.     test al,0a0h            ; DC00 or CC00?
  446.     je    memcfg_3
  447.     add bx,    00400h            ; Yes, make xC00
  448. memcfg_3:
  449.     mov mem_base,bx            ; Remember segment addr of memory
  450.     or    bx,bx
  451.     je    mem_works        ; don't test the memory if we use I/O.
  452. ; Set up Gate Array's Config Reg to enable and size the RAM.
  453.     setport    E33G_GACFR        ; Make sure gate array is set up and
  454.     mov al,    EGACFR_IRQOFF        ;  the RAM is enabled (not EPROM)
  455.     out dx,    al            ; ..
  456. ; Check the card's memory
  457.     mov ax,    mem_base        ; Set segment of the shared memory
  458.     add ax,    16*SM_TSTART_PG        ;  which starts 2000h up from "base"
  459.     mov cx,    2000h            ; Length of RAM to test
  460.     call    memory_test        ; Check it out
  461.     jz    mem_works        ; Go if it's OK
  462.     jmp    mem_busted        ; Go report failure if it's bad
  463. mem_works:
  464. ; Set up control of shared memory, buffer ring, etc.
  465.     loadport
  466.     setport    E33G_STARTPG        ; Set ASIC copy of rx's first buffer page
  467.     mov al,    SM_RSTART_PG
  468.     out dx,    al
  469.     setport    E33G_STOPPG        ;  and ASIC copy of rx's last buffer page + 1
  470.     mov al,SM_RSTOP_PG
  471. ;    mov al,    byte ptr sm_rstop_ptr
  472.     out dx,    al
  473. ; Set up interrupt/DMA control register in ASIC.
  474. ; For now, we won't use the DMA, so B0-B3 are zero.
  475.     xor ah,    ah            ; Get the interrupt level from arg line
  476.     mov al,    int_no            ; ..
  477.     cmp al,    9            ; If converted to 9, make back into 2
  478.     jne    get_irq1        ; Not 9
  479.     mov al,    2            ; Card thinks it's IRQ2
  480. get_irq1:                ; Now should have level in range 2-5
  481.     sub ax,    2            ; Make 0-3 for tables
  482.     cmp ax,    5-2            ; In range?
  483.     jna    get_irq2
  484.     mov    dx,offset cfg_err_msg
  485.     jmp    error            ; If not, can't configure.
  486. get_irq2:
  487.     xor cx,    cx            ; Make the bit for the ASIC
  488.     mov cl,    al            ; Shift count
  489.     mov al,    10h            ; Bit for irq2
  490.     shl al,    cl            ; Shift over as needed.
  491.     setport    E33G_IDCFR        ; Point at ASIC reg for IRQ level
  492.     out dx,    al            ; Set the bit
  493.     setport    E33G_NBURST        ; Set burst size to 8
  494.     mov al,    8
  495.     out dx,    al            ; ..
  496.     setport    E33G_DMAAH        ; Set up transmit bfr in DMA addr
  497.     mov al,    SM_TSTART_PG
  498.     out dx,    al
  499.     xor ax,    ax
  500.     setport E33G_DMAAL
  501.     out dx,    al
  502.     ret
  503.  
  504.  
  505. mem_busted:
  506.     mov dx,    offset mem_busted_msg
  507. error:
  508.     mov    ah,9        ; Type the msg
  509.     int    21h
  510.     stc            ; Indicate error
  511.     ret            ; Return to common code
  512.  
  513.  
  514.     public    print_parameters
  515. print_parameters:
  516.     mov di,    offset int_no        ; May override interrupt channel
  517.     mov dx,    offset int_no_name    ; Message for it
  518.     call    print_number
  519.     mov di,    offset io_addr        ; May override I/O address
  520.     mov dx,    offset io_addr_name    ; Message for it
  521.     call    print_number
  522.     mov    dx,offset thin_msg
  523.     cmp    thin_not_thick,0        ; May override thick/thin cable flag
  524.     jne    print_parameters_1
  525.     mov    dx,offset thick_msg
  526. print_parameters_1:
  527.     mov    ah,9
  528.     int    21h
  529.     ret
  530.  
  531.     include memtest.asm
  532.  
  533. code    ends
  534.  
  535.     end
  536.